#include "NetworkServer.h"

// =====================================================================
//      PUBLIC
// =====================================================================

NetworkServer::~NetworkServer()
{
    client_sockets_mutex.Acquire();
    
    forall(it,client_sockets) close(*it);
    
    client_sockets_mutex.Release();
}

void NetworkServer::Connect(int port)
{
    // Create server socket
    _sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    // 
    struct sockaddr_in adr;
    adr.sin_family = AF_INET;
    adr.sin_port = htons(port);
    adr.sin_addr.s_addr = INADDR_ANY;
    memset(adr.sin_zero,0,8);

    // 0=success, -1=fail
    if( bind(_sock_fd, (struct sockaddr*) &adr, sizeof(adr)) <0 )
        ApplicationLog::Print("NetworkServer::Connect - binding socket",ApplicationLog::FATAL);

    // listen to up to 5 simultaneous connections
    listen(_sock_fd,5);
    
    ApplicationLog::Print("NetworkServer::Connect - Server running on port ",port,ApplicationLog::INFO);

    Initialize();
}

bool NetworkServer::Broadcast(NetworkMessage* msg)
{
    forall(it,client_sockets)
        Send(*it,msg);
}

Event<int>& NetworkServer::OnNewConnection()
{
    return _new_connection_event;
}

Event<int>& NetworkServer::OnConnectionClosed()
{
    return _connection_closed_event;
}

// =====================================================================
//      PROTECTED
// =====================================================================

 // @Override Network :THREADED:
void NetworkServer::PrepareSet()
{
    // add server socket into set
    FD_SET(_sock_fd, &ready);
    
    // biggest socket until here is the server socket
    maxsock = _sock_fd+1;
    
    client_sockets_mutex.Acquire();
    
    // add each client socke into set
    forall(it,client_sockets){
        FD_SET(*it, &ready);
        if( *it+1 > maxsock ) maxsock = *it+1;
    }
    
    client_sockets_mutex.Release();
}

 // @Override Network :THREADED:
void NetworkServer::HandleActiveSockets()
{
    /* Handle new connection */
    if(FD_ISSET(_sock_fd,&ready))
        HandleNewClient();
    
    client_sockets_mutex.Acquire();
    
    /* Handle new messages */
    forall(it,client_sockets)
        if(FD_ISSET(*it,&ready))
            HandleNewData(*it);
    
    client_sockets_mutex.Release();
}

 // @Override Network :THREADED:
 /*
  * Como solo se llama desde HandleNewData, donde ya pedi
  * client_sockets_mutex, no hace falta pedirlo aca.
  * Es mas, si lo pido se cuelga.
  * */
void NetworkServer::LostConnectionHandler(int target_sockfd)
{
    close(target_sockfd);
    client_sockets.erase(target_sockfd);
    
    _connection_closed_event.Notify(target_sockfd);
}

// =====================================================================
//      PRIVATE
// =====================================================================

void NetworkServer::HandleNewClient()
{
    struct sockaddr_in cli_addr; socklen_t cli_len;
    cli_len = sizeof(cli_addr);
    
    // Accept new client when a new client arrives (blocking)
    int new_client_fd = accept(_sock_fd, (struct sockaddr*) &cli_addr, &cli_len);
    
    if( new_client_fd < 0 )
    {
        ApplicationLog::Print("NetworkServer::HandleNewClient - Error accepting client",ApplicationLog::ERROR);
    }
    else
    {
        // Add client to active client list
        client_sockets_mutex.Acquire();
        client_sockets.insert(new_client_fd);
        client_sockets_mutex.Release();
        
        ApplicationLog::Print("NetworkServer::HandleNewClient - Connected new client with sockfd ",new_client_fd,ApplicationLog::INFO);
        
        _new_connection_event.Notify(new_client_fd);
    }
}


